using System;
using dnAnalytics.Math;
using NUnit.Framework;

namespace dnAnalytics.Tests
{
    public static class TestHelper
    {
        public static void TestRelativeError(Complex expected, Complex approx, double acceptableError)
        {
            TestRelativeError(expected.Real, approx.Real, acceptableError);
            TestRelativeError(expected.Imaginary, approx.Imaginary, acceptableError);
        }

        public static void TestRelativeError(Complex32 expected, Complex32 approx, float acceptableError)
        {
            TestRelativeError(expected.Real, approx.Real, acceptableError);
            TestRelativeError(expected.Imaginary, approx.Imaginary, acceptableError);
        }
        
        public static void TestSignificatDigits( double expected, double approx, int digits)
        {
            double significantFigureMagnitude = System.Math.Pow(10, -(digits-1))/2.0;

            double diff = System.Math.Abs(expected - approx);
            bool pass = diff < significantFigureMagnitude;
            if(!pass)
            {
                Console.WriteLine("{0} : {1} : {2} : {3}", expected, approx, diff, significantFigureMagnitude);
            }
            Assert.IsTrue(pass);
        }

        public static void TestRelativeError(double expected, double approx, double acceptableError)
        {

            if (approx == expected || FloatingPointUtilities.EqualsWithinSignificantFigures(expected, approx, 15))
            {
                return;
            }
            double relativeError;
            if (FloatingPointUtilities.EqualsWithinSignificantFigures(expected, 0,15) || FloatingPointUtilities.EqualsWithinSignificantFigures(approx, 0,15))
            {
                relativeError = System.Math.Abs((approx - expected));
            }
            else
            {
                relativeError = System.Math.Abs((approx - expected)/expected);
            }

            Assert.IsFalse(double.IsNaN(relativeError));
            Assert.IsFalse(double.IsInfinity(relativeError));
            Assert.Less(relativeError, acceptableError);
        }

        public static void TestRelativeError(float expected, float approx, float acceptableError)
        {

            if (approx == expected || FloatingPointUtilities.EqualsWithinSignificantFigures(expected, approx, 7))
            {
                return;
            }
            double relativeError;
            if (FloatingPointUtilities.EqualsWithinSignificantFigures(expected, 0, 7) || FloatingPointUtilities.EqualsWithinSignificantFigures(approx, 0, 7))
            {
                relativeError = System.Math.Abs((approx - expected));
            }
            else
            {
                relativeError = System.Math.Abs((approx - expected) / expected);
            }

            Assert.IsFalse(double.IsNaN(relativeError));
            Assert.IsFalse(double.IsInfinity(relativeError));
            Assert.Less(relativeError, acceptableError);
        }
    }
}